﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.CodeDom;
using System.CodeDom.Compiler;
using Devtm.Generator.ModelStacks;
using Devtm.Common;
using System.Xml.Linq;

namespace Devtm.Generator.Writers
{


    public class XmlWriter
        : IWriter, IStackItem
    {


        private Project project;


        public XmlWriter()
        {
            StackElements = new CustomStack<XElement>(this);
        }

        public void Initialize(Project project, string extension = "")
        {
            this.project = project;

            if (string.IsNullOrEmpty(extension))
                this.Extension = ".xml";
            else
                this.Extension = extension;

            if (!this.Extension.StartsWith("."))
                this.Extension = "." + this.Extension;


        }

        public string Extension { get; set; }

        public System.IO.FileInfo File { get; set; }

        public bool Save(FileInfo file)
        {
            File = file;
            return Save();
        }


        public bool Save()
        {


            if (File.IsNull())
                throw this.NullReferenceException("Writer.File");


            File = File.Extension == Extension
               ? File
               : new FileInfo(File.FullName + Extension);


            if (!File.Directory.Exists)
                File.Directory.Create();


            using (var o = File.OpenWrite())
            {
                using (var p = new StreamWriter(o))
                {
                    using (var writer = System.Xml.XmlWriter.Create(o, new System.Xml.XmlWriterSettings() { Indent = true, ConformanceLevel = System.Xml.ConformanceLevel.Document }))
                    {

                        Elements.WriteTo(writer);
                        writer.Flush();
                    }
                }
            }

            return true;

        }



        private XElement Elements;
        private CustomStack<XElement> StackElements;




        public XComment AddComment(string comment)
        {
            var e = StackElements.Peek().Item;
            XComment i = new XComment(comment);
            e.Add(i);
            return i;
        }

        public XAttribute AddAttribute(string name, string @namespace, string value)
        {
            return AddAttribute(new XAttribute(XName.Get(name, @namespace), value));
        }


        public XAttribute AddAttribute(string name, string value)
        {
            return AddAttribute(new XAttribute(name, value));
        }


        public XAttribute AddAttribute(XName name, string value)
        {
            return AddAttribute(new XAttribute(name, value));
        }


        public XAttribute AddAttribute(System.Xml.Linq.XAttribute xElement)
        {
            var e = StackElements.Peek().Item;

            XAttribute attr = e.Attribute(xElement.Name);
            if (attr != null)
            {
                attr.Value = e.Value;
                return attr;
            }
            else
            {
                e.Add(xElement);
                return xElement;
            }
        }

        public StackContainer<XElement> AddElement(string name)
        {
            return AddElement(new XElement(name));
        }


        public StackContainer<XElement> AddElement(string name, string @namespace)
        {
            return AddElement(new XElement(XName.Get(name, @namespace)));
        }


        public StackContainer<XElement> AddElement(XName name)
        {
            return AddElement(new XElement(name));
        }


        public StackContainer<XElement> AddElement(System.Xml.Linq.XElement xElement)
        {

            StackContainer<XElement> result;

            if (Elements == null)
                Elements = xElement;

            else
            {
                if (StackElements.Count == 0)
                    Elements.Add(xElement);
                else
                    StackElements.Peek().Item.Add(xElement);
            }

            result = StackElements.AddBlock(xElement);

            return result;

        }




        public XElement Up()
        {
            var o = StackElements.Peek();
            o.Dispose();
            return o.Item;
        }


        public void Enter(object container)
        {

        }

        public void Exit(object container)
        {

        }


        public void GenerateXsdFor(FileInfo file)
        {

            var p = new StringBuilder();
            
            using (var writer = System.Xml.XmlWriter.Create(p, new System.Xml.XmlWriterSettings() { Indent = true, ConformanceLevel = System.Xml.ConformanceLevel.Document }))
            {

                System.Xml.XmlReader reader = System.Xml.XmlReader.Create(file.FullName);
                System.Xml.Schema.XmlSchemaSet schemaSet = new System.Xml.Schema.XmlSchemaSet();
                System.Xml.Schema.XmlSchemaInference schema = new System.Xml.Schema.XmlSchemaInference();
                schemaSet = schema.InferSchema(reader);
                foreach (System.Xml.Schema.XmlSchema s in schemaSet.Schemas())
                    s.Write(writer);

                writer.Flush();

            }

            Elements = XElement.Parse(p.ToString());

        }


        public EnumType ContentType
        {
            get { return EnumType.Xml; }
        }

    }

}
